package electionView;

import javax.swing.*;

import electionCtrl.Candidate;
import electionCtrl.Election;
import electionCtrl.Vote;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;

public final class VoteGui extends ElectionGui
{
	public enum Button
	{
		REVIEW_VOTE,CLEAR_VOTES;
		
		public String toString()
		{
			String str = super.toString();
			return str.substring(0,1) + str.substring(1).toLowerCase().replaceAll("_", " ");
		}
	};
	
	private Button action;
	
	private final List<Collection<Candidate>> candidatesInSeats;
	/**
	 * This isntance field is the frame that contains the choices for each seat.
	 */
	private final JPanel[] seatSelection;

	/**
	 * This instance field is used to create the array of JPanels.
	 */
	private final JPanel[] electionPanel;

	/**
	 * This instance field is the array of  Radiobuttons of size however many candidates.
	 */
	private final JRadioButton[][] candidateButtons;
	/**
	 * This instance field is the button group that is used in order to group the correct Radio buttons together.
	 */
	
	private final List<ButtonGroup> buttonGroups;
	
	/**
	 * The main select button, to replace the old sets of select buttons.
	 */
	private final JButton submitButton;

	/**
	 * This button is used to clear all the choices.
	 */
	private final JButton clearButton;
	
	private final Vote[] currentVotes;

//	/**
//	 * This is used in order to be created in the ElectionGui object.
//	 **/
//	private OverviewGui electView;
	/**
	 * Goes through the candidate array and sorts each candidate.
	 * Then creates an array of radiobuttons.  
	 * @param candid This is the candidate array.
	 * @param election This is the Election object.
	 **/
	public VoteGui(Election election, Semaphore semaphore)
	{
		super(election, new JFrame("Ballot"), semaphore);
		
		Candidate[] candidates = election.getCandidates();
		int numberOfSeats = Candidate.numOfSeatsPresent(candidates);
		
		this.seatSelection = new JPanel[numberOfSeats];
		this.electionPanel = new JPanel[numberOfSeats];
		this.currentVotes = new Vote[Candidate.Seat.values().length];
		
		this.candidatesInSeats = new LinkedList<Collection<Candidate>>();
		this.buttonGroups = new LinkedList<ButtonGroup>();
		int size = Candidate.Seat.values().length;
		for(int i = 0; i < size; i++)
		{
			this.candidatesInSeats.add(new LinkedList<Candidate>());
			this.buttonGroups.add(new ButtonGroup());
		}
		
		for(Candidate cand: candidates)
		{
			Collection<Candidate> list = this.candidatesInSeats.get(cand.seat.ordinal());
			list.add(cand);
		}
		
		this.candidateButtons = new JRadioButton[numberOfSeats][candidates.length];
		this.createButtons();
		this.submitButton = new JButton("Cast Vote");
		this.submitButton.addActionListener(new CastVoteButtonListener());
		this.clearButton = new JButton("Clear Choices");
		this.clearButton.addActionListener(new ClearVoteButtonListener());
		
		this.createFrames();
		this.mainFrame.setSize(Toolkit.getDefaultToolkit().getScreenSize());
		this.action = null;
	}
	
	/**
	 * Creates the buttons and adds them to the master list of buttons;
	 *  by running through the values of seat and checking each one.
	 **/
	private final void createButtons()
	{
		int removal = 0;
		for(Candidate.Seat seat: Candidate.Seat.values())
		{
			Collection<Candidate> list = this.candidatesInSeats.get(seat.ordinal());
			if (list.isEmpty())
			{
				removal++;
				continue;
			}
			int i = 0;
			for(Candidate c : list)
			{
				if(c.name !=null){
					this.candidateButtons[seat.ordinal()-removal][i] = new JRadioButton(c.name + " (" + c.party + ")");
					this.candidateButtons[seat.ordinal()-removal][i].addItemListener(new RadioButtonsListener());
				}
				i++;
			}
		}
		int count = 0;
		for(JRadioButton[] seat_Row: this.candidateButtons)
		{
			ButtonGroup currGroup = this.buttonGroups.get(count);
			for(JRadioButton j: seat_Row)
			{
				currGroup.add(j);
			}
			count++;
		}
	}
	
	/**
	 * This creates the frames for the gui. There is a problem with the election_Panel[panel_Count].add(j) line.
	 * I need help figuring out what the problem is.
	 **/
	private final void createFrames()
	{
		//used in order to initialize the Jframe with the correct spot in the array
		int removal = 0;
		//Use in order to add the radio button into the correct panel.
		int panel_Count =0;
		for(Candidate.Seat seat: Candidate.Seat.values())
		{
			int seatNumber = seat.ordinal();
			if(this.candidatesInSeats.get(seatNumber).isEmpty())
			{
				removal++;
				continue;
			}
			this.seatSelection[seatNumber-removal] = new JPanel();
			JLabel label = new JLabel(seat.toString());
			label.setHorizontalAlignment(SwingConstants.CENTER);
			this.seatSelection[seatNumber-removal].add(label);
			this.seatSelection[seatNumber-removal].setBorder(BorderFactory.createLineBorder(Color.black));
			this.seatSelection[seatNumber-removal].setVisible(true);
			this.seatSelection[seatNumber-removal].setLayout(new GridLayout(2,1));
			this.electionPanel[seatNumber-removal] = new JPanel();
			this.electionPanel[seatNumber-removal].setLayout(new GridLayout(2,1));
		}
		for(JRadioButton[] seat_Row: candidateButtons)
		{
			for(JRadioButton j: seat_Row)
			{
				if(j != null){
					electionPanel[panel_Count].add(j);
				}
			}
			panel_Count++;
		}
		for(int i = 0; i < electionPanel.length; i++)
		{
			seatSelection[i].add(electionPanel[i],BorderLayout.NORTH);
		}

		this.mainFrame.setSize(450,300);
		this.mainFrame.getContentPane().setLayout(new BoxLayout(mainFrame.getContentPane(),BoxLayout.Y_AXIS));
		JPanel miniballots = new JPanel();
		miniballots.setLayout(new GridLayout(2,2));
		for(int i = 0; i < this.electionPanel.length;i++)
		{
			Component[] components = this.electionPanel[i].getComponents();
			if(components.length > 0){
				miniballots.add(this.seatSelection[i]);
			}
		}
		JPanel submitPanel = new JPanel();
		submitPanel.add(this.submitButton);
		submitPanel.add(this.clearButton);
		this.mainFrame.add(miniballots);
		this.mainFrame.add(submitPanel);
	}

//	/**
//	 * Gets the seat of the candidate for sorting purposes.
//	 * @param seat This is used in order to sort the candidates into the correct Seat.
//	 * @return This returns an ArrayList of type Candidate.
//	 **/
//	private final Collection<Candidate> find_Seat(Candidate.Seat seat)
//	{
//		switch(seat)
//		{
//			case GOVERNOR:
//				return governer;
//			case US_SENATE:
//				return us_Senate;
//			case US_HOUSE:
//				return us_House;
//			case PENN_HOUSE:
//				return penn_House;
//			case PENN_SENATE:
//				return penn_Senate;
//			default:
//				throw new IllegalArgumentException("Error value doesn't match Seat. You Fail.");
//		}
//	}
	
	private class RadioButtonsListener implements ItemListener
	{
		/**
		 * This gets the name of the object that has been changed.
		 */
		public void itemStateChanged(ItemEvent e)
		{
			if(e.getStateChange() == ItemEvent.DESELECTED)
			{
				return;
			}
			String pressed = e.getItemSelectable().getSelectedObjects()[0].toString();
			for(Candidate c : election.getCandidates())
			{
				if(pressed.equals(c.name + " (" + c.party + ")"))
				{
					currentVotes[c.seat.ordinal()] = new Vote(c);
					break;
				}
			}
		}
	}
	
	private class ClearVoteButtonListener implements ActionListener
	{
		/**
		 * This method clears all the submitted choices on click.
		 */
		public void actionPerformed(ActionEvent event) 
		{
			clearAllSelections();
			for(int i = 0; i < currentVotes.length; i++)
			{
				currentVotes[i] = null;
			}
		}
	}
	
	public void clearAllSelections()
	{
		for(ButtonGroup bg : this.buttonGroups)
		{
			bg.clearSelection();
		}
	}

	public void clearAllVotes()
	{
		for(int i = 0; i < this.currentVotes.length; i++)
		{
			this.currentVotes[i] = null;
		}
	}
	
	private class CastVoteButtonListener implements ActionListener
	{
		/**
		 * This is the method that gives the buttons functionality. It matches the string gotten from the the e.getACtionCommand()
		 * and then does each seperate statements.
		 * @param e This is the ActionEvent that makes everything happen.
		 **/
		public void actionPerformed(ActionEvent e)
		{
			action = Button.REVIEW_VOTE;
			releaseResources();
		}
	}
	
	public Vote[] getVotes()
	{
		return this.currentVotes;
	}

	public Button waitForAction() throws InterruptedException
	{
		this.acquireResources();
		Button b = this.action;
		this.action = null;
		return b;
	}
}
